package licode.unisop.single.platform.infrastructure.repository.dao;

import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson2.JSON;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.github.yulichang.base.MPJBaseServiceImpl;
import com.github.yulichang.wrapper.MPJLambdaWrapper;
import licode.unisop.provider.conf.SiAssetState;
import licode.unisop.provider.info.*;
import licode.unisop.provider.vo.SiAssetBrief;
import licode.unisop.provider.vo.SiAssetEntity;
import licode.unisop.provider.vo.SiPageResult;
import licode.unisop.provider.vo.SiProps;
import licode.unisop.single.platform.application.gateway.PlatAssetDao;
import licode.unisop.single.platform.application.info.SiAssetRemove;
import licode.unisop.single.platform.infrastructure.assembler.UniPlatformSingleAssembler;
import licode.unisop.single.platform.infrastructure.repository.mapper.PlatAssetMapper;
import licode.unisop.single.platform.infrastructure.repository.po.PlatAssetRelPO;
import licode.unisop.single.platform.infrastructure.repository.po.PlatformAssetPO;
import licode.unisop.single.platform.infrastructure.utils.PageUtil;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.io.Serializable;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.stream.Collectors;

/**
 * uni-platform-single
 *
 * @author licode
 * @date 2016-08-27 15:30:58
 */
@Component
public class PlatAssetDaoImpl
        extends MPJBaseServiceImpl<PlatAssetMapper, PlatformAssetPO>
        implements PlatAssetDao {
    @Resource
    private UniPlatformSingleAssembler uniPlatformSingleAssembler;

    @Override
    public void add(SiAssetEntity item) {
        if (null == item.getProps()) {
            item.setProps(new HashMap<>());
        }
        super.save(uniPlatformSingleAssembler.fromPlatAssetEntity(item));
    }

    @Override
    public void update(SiAssetEntity item) {
        String strProps = null == item.getProps() ? null : JSON.toJSONString(item.getProps());
        super.lambdaUpdate()
                .set(item.getCode() != null, PlatformAssetPO::getCode, item.getCode())
                .set(item.getRootId() != null, PlatformAssetPO::getRootId, item.getRootId())
                .set(item.getParentId() != null, PlatformAssetPO::getParentId, item.getParentId())
                .set(item.getName() != null, PlatformAssetPO::getName, item.getName())
                .set(item.getLevel() != null, PlatformAssetPO::getLevel, item.getLevel())
                .set(item.getState() != null, PlatformAssetPO::getState, item.getState())
                .set(PlatformAssetPO::getProps, strProps)
                .set(PlatformAssetPO::getUpdateTime, LocalDateTime.now())
                .eq(PlatformAssetPO::getOwnerId, item.getOwnerId())
                .eq(PlatformAssetPO::getId, item.getId())
                .update();
    }

    @Override
    public void removeWithId(Serializable id) {
        super.removeById(id);
    }

    @Override
    public boolean exist(Serializable id) {
        return super.lambdaQuery().eq(PlatformAssetPO::getId, id).count() > 0;
    }

    @Override
    public void removeAssets(SiAssetRemove info) {
        super.remove(Wrappers.<PlatformAssetPO>lambdaUpdate()
                .eq(PlatformAssetPO::getOwnerId, info.getPlatformId())
                .in(PlatformAssetPO::getId, info.getIds()));
    }

    @Override
    public Long getSubAssetCount(SiAssetLookupIn lookupIn) {
        return super.lambdaQuery()
                .eq(PlatformAssetPO::getOwnerId, lookupIn.getOwnerId())
                .eq(PlatformAssetPO::getParentId, lookupIn.getAssetId())
                .eq(PlatformAssetPO::getType, lookupIn.getAssetType())
                .ne(PlatformAssetPO::getState, SiAssetState.AT_DELETED)
                .count();
    }

    @Override
    public SiAssetBrief getAssetBrief(SiAssetLookupIn lookupIn) {
        return null;
    }

    @Override
    public SiAssetEntity getWithId(Serializable id) {
        return uniPlatformSingleAssembler.fromPlatAsset(super.getById(id));
    }

    @Override
    public SiAssetEntity getPlatAsset(SiAssetId idInfo) {
        return uniPlatformSingleAssembler.fromPlatAsset(super.lambdaQuery()
                .eq(PlatformAssetPO::getOwnerId, idInfo.getOwnerId())
                .eq(PlatformAssetPO::getId, idInfo.getAssetId())
                .eq(PlatformAssetPO::getType, idInfo.getAssetType())
                .ne(PlatformAssetPO::getState, SiAssetState.AT_DELETED)
                .one());
    }

    @Override
    public SiAssetEntity lookupAsseByCode(SiLookupAssetByCodeIn lookupIn) {
        return uniPlatformSingleAssembler.fromPlatAsset(super.lambdaQuery()
                .eq(PlatformAssetPO::getOwnerId, lookupIn.getPlatformId())
                .eq(PlatformAssetPO::getCode, lookupIn.getCode())
                .eq(PlatformAssetPO::getType, lookupIn.getAssetType())
                .ne(PlatformAssetPO::getState, SiAssetState.AT_DELETED)
                .one());
    }

    @Override
    public List<SiAssetEntity> getPlatAssets(SiAssetIds idsInfo) {
        List<PlatformAssetPO> res = super.lambdaQuery()
                .eq(PlatformAssetPO::getOwnerId, idsInfo.getOwnerId())
                .eq(StrUtil.isNotBlank(idsInfo.getAssetType()),
                        PlatformAssetPO::getType, idsInfo.getAssetType())
                .in(null != idsInfo.getIds() && !idsInfo.getIds().isEmpty(),
                        PlatformAssetPO::getId, idsInfo.getIds())
                .ne(PlatformAssetPO::getState, SiAssetState.AT_DELETED)
                .list();
        return uniPlatformSingleAssembler.fromPlatAsset(res);
    }

    @Override
    public List<SiAssetEntity> getAuthPlatAssets(SiAssetIds idsInfo) {
        List<PlatformAssetPO> res = super.lambdaQuery()
                .eq(PlatformAssetPO::getOwnerId, idsInfo.getOwnerId())
                .eq(StrUtil.isNotBlank(idsInfo.getAssetType()),
                        PlatformAssetPO::getType, idsInfo.getAssetType())
                .in(null != idsInfo.getIds() && !idsInfo.getIds().isEmpty(),
                        PlatformAssetPO::getId, idsInfo.getIds())
                .eq(PlatformAssetPO::getState, SiAssetState.AT_ACTIVATE)
                .list();
        return uniPlatformSingleAssembler.fromPlatAsset(res);
    }

    @Override
    public List<SiAssetEntity> getPlatAssetsByRootId(SiRootId idInfo) {
        List<PlatformAssetPO> res = super.lambdaQuery()
                .eq(PlatformAssetPO::getOwnerId, idInfo.getPlatformId())
                .eq(StrUtil.isNotBlank(idInfo.getAssetType()),
                        PlatformAssetPO::getType, idInfo.getAssetType())
                .eq(PlatformAssetPO::getRootId, idInfo.getRootId())
                .ne(PlatformAssetPO::getState, SiAssetState.AT_DELETED)
                .list();
        return uniPlatformSingleAssembler.fromPlatAsset(res);
    }

    @Override
    public List<SiAssetBrief> findAssetList(AssetListInfo info) {
        return convertAssetList(super.lambdaQuery()
                .eq(PlatformAssetPO::getOwnerId, info.getPlatformId())
                .eq(info.getParentId() != null, PlatformAssetPO::getParentId, info.getParentId())
                .eq(StrUtil.isNotBlank(info.getAssetType()), PlatformAssetPO::getType, info.getAssetType())
                .in((null != info.getAssetIds() && !info.getAssetIds().isEmpty()), PlatformAssetPO::getId, info.getAssetIds())
                .like(StrUtil.isNotBlank(info.getName()), PlatformAssetPO::getName, info.getName())
                .like(StrUtil.isNotBlank(info.getCode()), PlatformAssetPO::getCode, info.getCode())
                .eq(info.getState() != null, PlatformAssetPO::getState, info.getState())
                .ne(PlatformAssetPO::getState, SiAssetState.AT_DELETED)
                .list());
    }

    @Override
    public SiPageResult<SiAssetBrief> findAssetPage(AssetPageInfo info) {
        Page<PlatformAssetPO> page = new Page<>(info.getCurrent(), info.getPageSize());
        page = getBaseMapper().selectJoinPage(page, PlatformAssetPO.class, new MPJLambdaWrapper<PlatformAssetPO>()
                .selectAll(PlatformAssetPO.class)
                .eq(PlatformAssetPO::getOwnerId, info.getPlatformId())
                .eq(StrUtil.isNotBlank(info.getAssetType()), PlatformAssetPO::getType, info.getAssetType())
                .eq(info.getParentId() != null, PlatformAssetPO::getParentId, info.getParentId())
                .like(StrUtil.isNotBlank(info.getName()), PlatformAssetPO::getName, info.getName())
                .like(StrUtil.isNotBlank(info.getCode()), PlatformAssetPO::getCode, info.getCode())
                .eq(info.getState() != null, PlatformAssetPO::getState, info.getState())
                .eq(StrUtil.isNotBlank(info.getParentId()), PlatformAssetPO::getParentId, info.getParentId())
                .notIn(null != info.getFilterAssets() && !info.getFilterAssets().isEmpty(),
                        PlatformAssetPO::getId, info.getFilterAssets())
                .ne(PlatformAssetPO::getState, SiAssetState.AT_DELETED));

        return PageUtil.convertPage(page, this::convertAssetList);
    }

    @Override
    public SiPageResult<SiAssetBrief> findHoldAssetPage(HoldAssetPageInfo req) {
        Page<PlatformAssetPO> page = new Page<>(req.getCurrent(), req.getPageSize());

        page = getBaseMapper().selectJoinPage(page, PlatformAssetPO.class, new MPJLambdaWrapper<PlatformAssetPO>()
                .selectAll(PlatformAssetPO.class)
                .leftJoin(PlatAssetRelPO.class, PlatAssetRelPO::getOwnerId, PlatformAssetPO::getOwnerId)
                .eq(PlatAssetRelPO::getAssetId, req.getHoldId())
                .eq(PlatAssetRelPO::getAssetType, req.getHoldType())
                .eq(PlatAssetRelPO::getTargetType, req.getAssetType())
                .groupBy(PlatformAssetPO::getId)
                .orderByDesc(PlatAssetRelPO::getUpdateTime));

        return PageUtil.convertPage(page, this::convertAssetList);
    }

    @Override
    public SiPageResult<SiAssetBrief> findAssetHoldPage(AssetHoldPageInfo req) {
        Page<PlatformAssetPO> page = new Page<>(req.getCurrent(), req.getPageSize());

        page = getBaseMapper().selectJoinPage(page, PlatformAssetPO.class, new MPJLambdaWrapper<PlatformAssetPO>()
                .selectAll(PlatformAssetPO.class)
                .leftJoin(PlatAssetRelPO.class, PlatAssetRelPO::getOwnerId, PlatformAssetPO::getOwnerId)
                .eq(PlatAssetRelPO::getTargetId, req.getAssetId())
                .eq(PlatAssetRelPO::getTargetType, req.getAssetType())
                .eq(PlatAssetRelPO::getAssetType, req.getHoldType())
                .groupBy(PlatformAssetPO::getId)
                .orderByDesc(PlatAssetRelPO::getUpdateTime));

        return PageUtil.convertPage(page, this::convertAssetList);
    }

    private List<SiAssetBrief> convertAssetList(List<PlatformAssetPO> relList) {
        if (null != relList) {
            return relList.stream().map(item -> {
                SiAssetBrief brief;
                brief = uniPlatformSingleAssembler.toAssetBrief(item);
                if (null == brief.getProps()) {
                    brief.setProps(new SiProps());
                }
                brief.getProps().addProp("createTime", item.getCreateTime());
                return brief;
            }).collect(Collectors.toList());
        } else {
            return new ArrayList<>();
        }
    }
}
